跳到主要内容

使用 Docker 资源

此教程中的所有示例镜像都在 https://github.com/lulaide/docker-example/

Volume 存储卷

volume

Volume 是 Docker 官方管理的“持久化存储机制”,用来保存容器生命周期之外仍然保留的数据,例如数据库、日志、文件存储等。

容器删了 → 数据还在 容器更新、重建 → 数据不丢

Volume 是 Docker 推荐的数据持久化方式,比 bind mount 更安全、更便携,且可跨容器共享。

Volume 三种类型:

Named Volume(命名卷)——最常用

由 Docker 管理,默认存储在:

/var/lib/docker/volumes/<volume_name>/_data/

创建命名卷

docker volume create <volume_name>

查看所有卷

docker volume ls

删除卷

docker volume rm <volume_name>

这里使用一个 Minecraft 服务器利用 Volume 来保存 主世界地图 的例子:

创建储存卷

docker volume create mc_world

运行 Minecraft 容器,并挂载储存卷

docker run -itd -p 25565:25565 -v mc_world:/app/world --name mc1.12.2 ghcr.io/lulaide/paper:1.12.2

进入游戏后对世界进行一些修改,然后关闭服务器。 mc1.12.2

docker stop mc1.12.2

现在查看一下储存卷中的数据:

docker volume inspect mc_world

输出如下

[
{
"CreatedAt": "2025-xx-xxTxx:xx:xx+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/mc_world/_data",
"Name": "mc_world",
"Options": null,
"Scope": "local"
}
]

此目录内的内容即为 Minecraft 世界数据,原本 world 目录下的文件都在这里:

$ ls /var/lib/docker/volumes/mc_world/_data
advancements data level.dat level.dat_old playerdata region session.lock stats uid.dat

现在我们把游戏版本换为1.21.1,重新运行容器,并挂载同一个储存卷:

docker run -itd -p 25565:25565 -v mc_world:/app/world --name mc1.21.1 ghcr.io/lulaide/paper:1.21.1

再次进入游戏,发现之前的世界数据都还在,并且版本已经升级到 1.21.1 了: mc1.21.1

关闭服务器

docker stop mc1.21.1

删除容器

docker rm mc1.21.1

可以看到储存卷中的数据依然存在:

$ ls /var/lib/docker/volumes/mc_world/_data
advancements data datapacks entities level.dat level.dat_old paper-world.yml playerdata region session.lock stats uid.dat

特点:

  • 自动管理路径
  • 跨容器共享
  • 容器删除不会删除卷

Anonymous Volume(匿名卷)

及其不推荐使用匿名卷,因为无法轻易管理和定位数据。 匿名卷是没有命名的 Volume,Docker 会自动分配一个随机名称。只有两种情况会出现匿名卷:

镜像里写了 VOLUME 指令

这里以官方的 MySQL 镜像为例:

docker run --rm -e MYSQL_ROOT_PASSWORD=root mysql:latest

运行前只有一个卷:

$ docker volume ls
DRIVER VOLUME NAME
local mc_world

运行后会多出一个匿名卷:

$ docker volume ls
DRIVER VOLUME NAME
local ed7410e0fe487b6b96975b935d6908e2cf3a2448983af184e2794a9e7c1fe8a2
local mc_world

这里储存这数据库数据

$ ls /var/lib/docker/volumes/ed7410e0fe487b6b96975b935d6908e2cf3a2448983af184e2794a9e7c1fe8a2/_data
auto.cnf ca-key.pem '#ib_16384_0.dblwr' ibtmp1 mysql.ibd private_key.pem sys
binlog.000001 ca.pem '#ib_16384_1.dblwr' '#innodb_redo' mysql.sock public_key.pem undo_001
binlog.000002 client-cert.pem ib_buffer_pool '#innodb_temp' mysql_upgrade_history server-cert.pem undo_002
binlog.index client-key.pem ibdata1 mysql performance_schema server-key.pem

更推荐的做法是使用命名卷,自己创建并挂载到容器中:

docker volume create mysql_data
docker run -d -e MYSQL_ROOT_PASSWORD=root -v mysql_data:/var/lib/mysql mysql:latest

运行容器时使用 -v 或 --volume 但没有指定卷名

创建匿名卷

docker run -v /app/ --rm ubuntu sh -c 'echo "Anonymous Volume" > /app/output.txt'

查看有哪些卷

docker volume ls

你会发现多了一个名字一长串的卷:

DRIVER    VOLUME NAME
local 4878daef9a83732adc44a771a5cd82a8a2730ea567a229487a4cbbcac4354fed
local mc_world

我们写入的 output.txt 文件的确保存在这个卷下。

cat /var/lib/docker/volumes/4878daef9a83732adc44a771a5cd82a8a2730ea567a229487a4cbbcac4354fed/_data/output.txt
Anonymous Volume

Host Bind Mount(绑定挂载)

直接把宿主的目录挂载到容器中:

docker run -v /path/on/host:/path/in/container ...

这种方式更灵活,可以直接访问宿主机的文件系统,但需要注意权限和路径问题。 简单理解:

容器内看到的路径 = 宿主机真实文件 修改任意一边 = 两边实时同步

Bind Mount 不属于 Docker Volume,它属于 Linux 内核的 bindfs(bind mount)机制。 当你执行:

-v /host:/container

Docker 并没有移动文件,也没有创建卷,只做了一件事: 宿主机 /host 映射为容器中的 /container 这部分行为在 namespace + mount namespace 下实现。

Network 网络

安装 docker 之后,默认会创建三种网络类型:

  • bridge(默认网络)
  • host(直接使用宿主机网络)
  • none(无网络)

还有其他类型:

  • macvlan(自定义 MAC 地址,适合物理网络集成)
  • ipvlan(类似 macvlan,但更灵活)
  • overlay(跨主机网络,Swarm 模式使用)

bridge(默认网络)

最常用,用得最多。 特点: Docker 创建一个虚拟交换机:docker0 容器通过 veth pair 接入 提供独立的内部 IP(如 172.17.0.x) 容器与容器之间可互通 外部访问需要端口映射 -p 示例: 注意创建自定义 bridge 网络网络之前只有一个 docker0 网络的默认桥接网络,创建自定义桥接网络后会多出一个新的桥接网络:

...
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 2a:b8:a6:3e:1e:47 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever

创建之后

...
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 2a:b8:a6:3e:1e:47 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
4: br-44c8aaa34eec: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 2e:65:bc:e1:c2:f7 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 brd 172.18.255.255 scope global br-44c8aaa34eec
valid_lft forever preferred_lft forever
docker network create mynet
docker run --network mynet nginx

适用场景:单机部署、容器互联

host(直接使用宿主机网络)

容器与宿主机共享网络命名空间: 无虚拟网卡 无 docker0 能使用,不能创建、不能删除、不能修改 性能最好 不需要 -p,直接监听宿主的端口 容易端口冲突 示例:

docker run --network host nginx

适用场景: 高性能网络服务(数据库、监控) 需要访问宿主机局域网广播

none(无网络)

容器没有网络接口 适合安全隔离

macvlan(自定义 MAC 地址)

每个容器获得:

  • 局域网真实 IP
  • 独立 MAC 地址

示例: 创建 macvlan 网络:

docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 pubnet

运行容器并指定 IP:

docker run -it --rm --network pubnet --ip 192.168.1.100 alpine sh

查看一下容器内的网络配置:

6: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
link/ether aa:b9:f2:57:29:d8 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.100/24 brd 192.168.1.255 scope global eth0
valid_lft forever preferred_lft forever

容器可被局域网设备直接访问。

Docker 创建 macvlan 网络时 --subnet 与 --gateway 只是 Docker 内部的“地址管理器”(IPAM),并不是实际网络必须使用的网段。 如果你打算让容器通过 DHCP 获取真实 IP,则可以随便填写“假网段 / 假网关”,甚至完全不使用。

ipvlan(类似 macvlan,但更灵活)

IPvlan(IPVLAN)是 Linux 内核的一种虚拟网络接口技术,与 Macvlan 类似,但逻辑完全不同。这里简单了解一下即可。 IPvlan 不给每个容器创建独立 MAC,而是全部共享宿主机的 MAC,只区分 IP。

创建模式为 l2 的 ipvlan 网络:

docker network create -d ipvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 \
-o ipvlan_mode=l2 \
ipvlan0
项目IPvlan L2IPvlan L3IPvlan L3S
工作层级二层(Layer 2)三层(Layer 3)三层(共享子网)
MAC 地址所有容器共享宿主机 MAC所有容器共享宿主机 MAC所有容器共享宿主机 MAC
IP 网段要求必须和宿主机同网段容器必须使用不同网段与宿主机相同网段
DHCP 支持✔ 支持(广播可达)❌ 不支持(广播不转发)❌ 不支持
容器→外部网络通过物理网络直接通通信通过宿主机路由转发也通过宿主机转发
容器←外部网络访问直接访问(像 macvlan)需额外路由需路由,但同网段更方便
容器间互通需要辅助路由(默认隔离)宿主机做三层转发宿主机做三层转发
容器访问宿主机默认不通(需创建 ipvlan 子接口)默认不通(需路由)默认不通(需路由)

CPU、内存、GPU 资源

CPU

  • --cpus 限制容器可用的 CPU 数(1.5 表示 1.5 个核心)
  • --cpuset-cpus 指定容器可使用哪些 CPU 核(如 0-3)
docker run --cpus="2.5" nginx
docker run --cpuset-cpus="0,2" nginx

内存

  • --memory 限制容器可用的内存大小(如 512m、2g)
  • --memory-swap 内存 + swap 总量
docker run -m 512m --memory-swap 1g nginx

GPU

  • --gpus 指定 GPU 数量(如 all, 0, 0,1)
docker run --gpus all nvidia/cuda:12.0-base
docker run --gpus '"device=0,1"' nvidia/cuda:12.0-base